package uicgas.pump.impl;

import java.util.Random;

import org.apache.log4j.Logger;

import uicgas.communication.Communication;
import uicgas.globaldata.ControlMessage;
import uicgas.globaldata.CreditCard;
import uicgas.globaldata.Messages;
import uicgas.globaldata.PumpState;
import uicgas.globaldata.SelfAnnouncement;
import uicgas.globaldata.States;
import uicgas.globaldata.Transaction;
import uicgas.globaldevice.CardReader;
import uicgas.globaldevice.MockPrinter;
import uicgas.globaldevice.Printer;
import uicgas.pump.PumpLogic;
import uicgas.pump.PumpStateChangeNotifiable;
import uicgas.pump.device.PhysicalPump.GasolineGrade;
import uicgas.pump.device.impl.MockPump;
import uicgas.pump.gui.impl.PumpGui;
import uicgas.tools.LogHelper;

public class PumpLogicImpl implements PumpLogic
{
	private static final Logger LOGGER = LogHelper
			.getLogger(PumpLogicImpl.class);

	private Communication communication = null;
	private MockPump physicalPump = null;
	private Printer printer = null;
	private PumpGui gui = null;

	private int id;
	private States currentState = null;
	private CreditCard cardInfo = null;

	public PumpLogicImpl()
	{
		id = Math.abs(new Random().nextInt());

		startGui();

		physicalPump = new MockPump(gui, this);
		printer = new MockPrinter();

		communication = new CommunicationImpl(this);
		communication.start();

		currentState = States.DEACTIVATED;
	}

	/**
	 * return the Communication component this pump holds
	 * 
	 * @return the Communication component
	 */
	public Communication getCommunication()
	{
		return communication;
	}

	private void startGui()
	{
		PumpGui frame = new PumpGui(this);
		PumpLogicImpl.this.gui = frame;
		frame.setResizable(false);
		frame.setVisible(true);
	}

	/*@Override
	public void announceSelfToStation()
	{
		SelfAnnouncement selfAnnouncement = new SelfAnnouncement(id, id);
		ControlMessage controlMessage = new ControlMessage(
				Messages.ANNOUNCESELF, selfAnnouncement);
		communication.sendData(controlMessage);
	}*/

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void swipeCard(CardReader cardReader)
	{
		cardInfo = cardReader.getCardData();
		sendCardInfoForValidation(cardInfo);
		processWaitingForValidationLogic();
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public States changeState(States newState)
	{
		if (LOGGER.isDebugEnabled())
		{
			LOGGER.debug("changeState - originalState[" + currentState
					+ "], newState[" + newState + "]. ");
		}

		States originalState = currentState;
		currentState = newState;

		notifyRegisterToChangeState(originalState);

		return originalState;
	}

	private void sendCardInfoForValidation(CreditCard card)
	{
		ControlMessage cardValicationMsg = new ControlMessage(
				Messages.VALIDATECARD, card);
		communication.sendData(cardValicationMsg);
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public int getID()
	{
		return id % 20;
	}

	/**
	 * {@inheritDoc}
	 */
	public void generateNewID()
	{
		id++;
		id = id % 20;
		//		id = id % 20;
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void activatePump(CreditCard card)
	{
		if (card != null)
		{
			cardInfo = card;
		}
		physicalPump.activePump();
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void deactivatePump()
	{
		physicalPump.deactivePump();
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void beginToPump()
	{
		physicalPump.startPumping();
	}

	//	@Override
	//	public void stopPumping()
	//	{
	//		physicalPump.stopPumping();
	//	}

	@Override
	/**
	 * {@inheritDoc}
	 * Called by this one -> PhysicalPump -> PumpGui
	 */
	public void finishPumping()
	{
		physicalPump.finishedPumping();
		chargeCreditCard();
		changeState(States.DEACTIVATED);
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void decommissionPump()
	{
		physicalPump.deactivePump();
		gui.setToOutOfServiceScreen();
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void recommissionPump()
	{
		gui.setToWelcomScreen();
	}

	private void notifyRegisterToChangeState(States originalState)
	{
		PumpState pumpState = new PumpState(originalState, currentState,
				getID());
		ControlMessage cardValicationMsg = new ControlMessage(
				Messages.CHANGEPUMPSTATE, pumpState);

		communication.sendData(cardValicationMsg);
	}

	private void chargeCreditCard()
	{
		Transaction transaction = getCurrentTransaction();
		communication.sendData(new ControlMessage(Messages.CHARGECREDITCARD,
				transaction));
	}

	/**
	 * {@inheritDoc}
	 */
	public Transaction getCurrentTransaction()
	{
		return new Transaction(physicalPump.getPumpedDollars(),
				physicalPump.getPumpedGallons(), cardInfo, getID());
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public boolean printReceipt()
	{
		Transaction transaction = getCurrentTransaction();
		return printer.printWithProbabilityFailed(transaction);
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void callForAssistance()
	{
		SelfAnnouncement announcement = new SelfAnnouncement(getID(), -1);
		communication.sendData(new ControlMessage(
				Messages.NOTIFYREGISTERASSISTANCENEEDED, announcement));
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void changeGrade(GasolineGrade grade)
	{
		physicalPump.changeGrade(grade);
	}

	private void processWaitingForValidationLogic()
	{
		gui.setToValidatingCardScreen();
	}

	/**
	 * {@inheritDoc}
	 */
	public States getCurrentState()
	{
		return currentState;
	}

	/**
	 * Add one PumpStateChangeNotifiable to listen pump's state changing
	 * 
	 * @param changeNotifiable listener
	 */
	public void addPumpStateChangeListener(
			PumpStateChangeNotifiable changeNotifiable)
	{
		if (changeNotifiable != null)
		{
			physicalPump.addPumpStateChangeListener(changeNotifiable);
		}
	}

	@Override
	public void cardInvalid()
	{
		gui.setToInValidateCardScreen();
	}

	@Override
	public void setShowingID(int id)
	{
		gui.setTitle("[" + (id + 1) + "]");
	}

}
